package byron.client;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

import org.apache.commons.collections.KeyValue;


import byron.server.CsvSource;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dev.util.collect.Lists;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedTabPanel;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.googlecode.gchart.*;
import com.googlecode.gchart.client.GChart;
import com.googlecode.gchart.client.GChart.SymbolType;

/*
 * This is the client. It works as a container for the other widgets.
 */
public class ByronClient implements EntryPoint {
	private DecoratedTabPanel tabPanel = new DecoratedTabPanel();
	private ByronServiceAsync ByronSvc = GWT.create(ByronService.class);

	private enum Axis{
		X_AXIS,
		Y_AXIS
	}
	
	public void onModuleLoad() {
		initTabPanel();
	}
	
	public FormPanel createFileUpload() {
	    final FormPanel uploadForm = new FormPanel();
	    uploadForm.setAction("/byron_braun/service");

	    uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
	    uploadForm.setMethod(FormPanel.METHOD_POST);

	    VerticalPanel panel = new VerticalPanel();
	    uploadForm.setWidget(panel);

	    final FileUpload upload = new FileUpload();
	    upload.setName("uploadFormElement");
	    panel.add(upload);

	    Button uploadSubmitButton = new Button("Submit");
	    panel.add(uploadSubmitButton);

	    uploadSubmitButton.addClickHandler(new ClickHandler() {
	      public void onClick(ClickEvent e) {
	        uploadForm.submit();
	      }
	    });

	    uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
			
			public void onSubmitComplete(SubmitCompleteEvent event) {
			    VerticalPanel vPanel = new VerticalPanel();
			    vPanel.add(createChart(chartType1()));
			    tabPanel.add(vPanel, "Chart 1");
			    
			    vPanel = new VerticalPanel();
			    vPanel.add(createChart(chartType2()));
			    tabPanel.add(vPanel, "Chart 2");
			    
			    vPanel = new VerticalPanel();
			    vPanel.add(createChart(chartType3()));
			    tabPanel.add(vPanel, "Chart 3");
			}
		});

	    return uploadForm;
	  }
	
	private GChart chartType1() {
		GChart c = new GChart();
		c.addCurve();
		c.setXChartSize(800);
		c.setYChartSize(800);
		c.setWidth("800px");
		c.setHeight("800px");
		return c;
	}
	
	private GChart chartType2() {
		GChart c = new GChart();
		c.addCurve();
	    c.getCurve().getSymbol().setSymbolType(SymbolType.VBAR_SOUTH);
	    c.getCurve().getSymbol().setBackgroundColor("red");
	    c.getCurve().getSymbol().setBorderColor("black");
	    c.getCurve().getSymbol().setModelWidth(1.0);

		c.setXChartSize(800);
		c.setYChartSize(800);
		c.setWidth("800px");
		c.setHeight("800px");
		return c;
	}
	
	private GChart chartType3() {
		GChart c = new GChart();
		c.addCurve();
	    c.getCurve().getSymbol().setSymbolType(SymbolType.LINE);
	    c.getCurve().getSymbol().setBackgroundColor("green");
	    c.getCurve().getSymbol().setBorderColor("black");
	    c.getCurve().getSymbol().setModelWidth(0.5);
	    c.getXAxis().setTickLabelFontSize(6);

		c.setXChartSize(800);
		c.setYChartSize(800);
		c.setWidth("800px");
		c.setHeight("800px");
		return c;
	}
	
	private void initTabPanel() {

	   tabPanel.setWidth("800px");
	    tabPanel.setAnimationEnabled(true);
	    
	    // Home page
	    VerticalPanel vPanel = new VerticalPanel();
	    vPanel.add(new Label("Select file to upload (only CSV):"));
	    vPanel.add(createFileUpload());
	    tabPanel.add(vPanel, "Home");
	    
	    // About page
	    vPanel = new VerticalPanel();
	    vPanel.add(new Image("http://byron-braun.googlecode.com/files/logo.png"));
	    tabPanel.add(vPanel, "About");
	   
	    
	    tabPanel.selectTab(0);
	    
	    RootPanel.get().add(tabPanel);
	}
	
	private ChartPanel createChart(GChart c) {
		final ChartPanel cp = new ChartPanel(c);
		
		// Get attributes
		setAttributes(cp);
		setSuggestions(cp);
		
		// Get data
		setColumns(cp, "Min", "100 ATS", Axis.X_AXIS);
		setColumns(cp, "Max", "100 ATS", Axis.Y_AXIS);

		//Add listeners.
		cp.addXBoxListener(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				ListBox box = ((ListBox)event.getSource());
				String value = box.getItemText(box.getSelectedIndex());
				setColumns(cp, value, cp.getKey(), Axis.X_AXIS);
				cp.getChart().getXAxis().setAxisLabel(value);
			}
		});
		cp.addYBoxListener(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				ListBox box = ((ListBox)event.getSource());
				String value = box.getItemText(box.getSelectedIndex());
				setColumns(cp, value, cp.getKey(), Axis.Y_AXIS);
				cp.getChart().getYAxis().setAxisLabel(value);
			}
		});
		cp.addSuggestionListener(new KeyPressHandler() {
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == 13) {
					String key = cp.getKey();
					setColumns(cp, cp.getXAttribute(), key, Axis.X_AXIS);
					setColumns(cp, cp.getYAttribute(), key, Axis.Y_AXIS);
				}
			}
		});
		return cp;
	}

	/**
	 * Retrieves column values according to the criterias
	 * @param cp Chartpanel affected
	 * @param attribute Attribute in database ("header")
	 * @param key Value of the primary key in the database
	 * @param axis X- or Y-axis?
	 */
	private void setColumns(final ChartPanel cp, String attribute, String key, final Axis axis) {
		AsyncCallback<List<CellData>> callbackCols = new AsyncCallback<List<CellData>>() {
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}

			public void onSuccess(List<CellData> result) {
				if (Axis.X_AXIS == axis) {
					cp.changeXValues(result);
				}
				else {
					cp.changeYValues(result);
				}
			}
		};
		ByronSvc.getColumn(attribute, key, callbackCols);
	}

	/**
	 * Retrieves the different attributes/headers from the database,
	 * and  populates the listboxes
	 * @param cp Chartpanel affected
	 */
	private void setAttributes(final ChartPanel cp) {
		AsyncCallback<List<String>> callbackHeaders = new AsyncCallback<List<String>>() {
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}

			public void onSuccess(List<String> result) {
				cp.setAttributes(result);
			}
		};
		ByronSvc.getHeaders(callbackHeaders);
	}
	
	/**
	 * Retrieves all primary key values from the database, and populates the
	 * suggestion box 
	 * @param cp Chartpanel affected
	 */
	private void setSuggestions(final ChartPanel cp) {
		AsyncCallback<List<CellData>> callback = new AsyncCallback<List<CellData>>() {
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}

			public void onSuccess(List<CellData> result) {
				List<String> suggs = new ArrayList<String>();
				for (CellData cd : result) {
					suggs.add(cd.toString());
				}
				cp.setSuggestions(suggs);
			}
		};
		ByronSvc.getColumn("Serie", "", callback);
	}
	
}